import React, {PureComponent, PropTypes} from 'react';

import styles from './style.scss';

import iScroll from 'iscroll/build/iscroll-probe';

export default class ScrollView extends PureComponent {
    constructor(props) {
        super();
        this.flag = false;
        this.cacheY = 0;
        this.state = {
            showFooter: false
        };
        this._touchmove = this._touchmove.bind(this);
        this._refresh = this._refresh.bind(this);
        this.scrollY = props.scrollToY;
    }

    static propTypes = {
        //是否开启flex布局
        flex: PropTypes.bool,
        //scrollView的容器高度
        height: PropTypes.string,
        //滚动回调
        onScroll: PropTypes.func,
        //到底部多像素执行onloadmore
        onEndReachedThreshold: PropTypes.number,
        //加载更多回调
        onloadMore: PropTypes.func,
        //加载底部
        renderFooter: PropTypes.func,
        //返回iscroll对象
        scroll: PropTypes.func,
        //滚动速度
        probeType: PropTypes.oneOf([1, 2, 3]),
        //滚动到哪里
        scrollToY: PropTypes.number,
        hasHeader:PropTypes.bool,
    };

    static defaultProps = {
        flex: false,
        height: "100%",
        onScroll: () => {},
        onloadMore: () => {},
        renderFooter: () => null,
        onEndReachedThreshold: 80,
        scroll: () => {},
        probeType: 2,
        scrollToY: 0,
        hasHeader:false
    };

    static childContextTypes = {
        iScroll: PropTypes.object,
    };

    getChildContext() {
        return {
            iScroll: this.iScroll
        };
    };

    componentDidMount() {
        this.initScroll();
        window.addEventListener('resize', this._refresh);
        window.addEventListener('touchmove', this._touchmove);
    };

    _touchmove(e) {
        e.preventDefault();
    };

    componentWillUnmount() {
        this.iScroll && this.iScroll.destroy();
        window.removeEventListener('resize', this._refresh);
        window.removeEventListener('touchmove', this._touchmove);
    };

    componentWillReceiveProps(nextProps) {
        if(this.scrollY !== nextProps.scrollToY ) {
            this.scrollY = nextProps.scrollToY;
            this.scrollTo();
        }
    };

    getDiff() {
        const {
            y,
            maxScrollY
        } = this.iScroll;
        if (y > 0 || Math.abs(y) > Math.abs(maxScrollY)) return false;
        return Math.abs(maxScrollY) - Math.abs(y);
    }

    _refresh() {
        this.iScroll &&
        setTimeout(() => this.iScroll.refresh(), 10);
    }

    canClick() {
        const userAgent = navigator.userAgent;
        if (/iPhone|iPad|iPod|Macintosh/i.test(userAgent)) return false;
        if (/Chrome/i.test(userAgent)) return (/Android/i.test(userAgent));
        if (/Silk/i.test(userAgent)) return false;
        if (/Android/i.test(userAgent)) {
            let s = userAgent.substr(userAgent.indexOf('Android') + 8, 3);
            return parseFloat(s[0] + s[3]) >= 44;
        }
    }

    initScroll() {
        const {
            scroll,
            probeType,
        } = this.props;

        this.iScroll = new iScroll(this.el, {
            mouseWheel: true,
            probeType: probeType,
            scrollbars: "custom",
            fadeScrollbars: true,
            click: this.canClick(),
            disablePointer: true,
            disableTouch: false,
            disableMouse: false,
            momentum: true
        });

        scroll(this.iScroll);

        this.iScroll.on("beforeScrollStart", () => {
            const diff = this.getDiff();
            if ( diff === false ) return;
            this.cacheY = diff;
            this.shouldRefresh();
        });

        this.iScroll.on('scroll', this.scrollEvent.bind(this));
        this.iScroll.on('scrollEnd', this.scrollEvent.bind(this));

        this.scrollTo();
    }

    scrollEvent() {

        const {
            onScroll,
            onloadMore,
            onEndReachedThreshold,
        } = this.props;

        const diff = this.getDiff();

        this.shouldRefresh();

        if (diff === false) return;

        if( Math.abs( diff - this.cacheY ) < 2 ) return;

        let direction = diff - this.cacheY > 0 ? 'down' : 'up';

        onScroll({
            scroller: this.iScroll,
            direction: direction
        });

        if (!this.flag && direction === 'up' && diff < onEndReachedThreshold) {
            onloadMore();
            this.flag = true;
        } else {
            if (diff > onEndReachedThreshold) {
                this.flag = false;
            }
        }

        this.cacheY = diff;
    }

    shouldRefresh(){
        const {scrollerHeight, scroller, wrapperHeight} = this.iScroll;
        const {clientHeight} = scroller;
        let refresh = false;
        if (this.el && this.el.clientHeight !== wrapperHeight) {
            refresh = true;
        }

        if (clientHeight !== scrollerHeight || refresh) {
            this._refresh();
        }
    }

    scrollTo() {
        this.iScroll.scrollTo(0, this.scrollY);
    }

    render() {
        const {children, flex, height, renderFooter , hasHeader } = this.props;
        const { showFooter } = this.state;
        return (
            <div
                style={{height: !flex ? height : "100%"}}
                className={classname(
                    styles.scroll_view,
                    flex && styles.scroll_view_flex_1,
                )}
                ref={e => this.el = e}
            >
                <div
                    className={styles.scroll_view_inner}
                    style={{
                        paddingTop:hasHeader? 46 : 0
                    }}
                >
                    {children}
                    <div className={styles.scroll_view_footer}>
                        {renderFooter()}
                    </div>
                </div>
            </div>
        )

    }

}
